package com.base.core.exception;

import com.base.core.enums.SystemCodeEnum;
import com.base.core.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
import org.apache.dubbo.rpc.service.GenericService;

import javax.validation.ConstraintViolationException;

@Slf4j
@Activate(group = CommonConstants.PROVIDER)
public class DubboExceptionFilter implements Filter, Filter.Listener {

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        return invoker.invoke(invocation);
    }

    @Override
    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
        if (appResponse.hasException() && GenericService.class != invoker.getInterface()) {
            // 获取异常
            Throwable exception = appResponse.getException();
            ServiceException e;

            // 如果为CommonException异常直接返回
            if (exception instanceof ServiceException) {
                appResponse.setException(null);
                appResponse.setValue(R.fail(SystemCodeEnum.FAILURE, exception.getMessage()));
                return;
            }

            // 参数校验异常
            if (exception instanceof ConstraintViolationException) {
                e = new ServiceException(SystemCodeEnum.PARAMETER_INCOMPLETE);
                String errMsg = String.format("请求参数不正确: %s",
                        ((ConstraintViolationException) exception).getConstraintViolations());
                e.setMessage(errMsg);
                appResponse.setException(e);
                return;
            }

            // 处理其他异常
            e = new ServiceException(SystemCodeEnum.FAILURE);
            String errMsg = String.format("调用 Service: %s, method: %s 发生异常 %s",
                    invocation.getTargetServiceUniqueName(),
                    invocation.getMethodName(),
                    exception.getCause());
            e.setMessage(errMsg);
            appResponse.setException(e);
        }
    }

    @Override
    public void onError(Throwable e, Invoker<?> invoker, Invocation invocation) {
        log.error("未检查或未声明的异常 " + RpcContext.getContext().getRemoteHost() +
                ". service: " + invoker.getInterface().getName() +
                ", method: " + invocation.getMethodName() +
                ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
    }
}
